package info.motteke.util.net;

import java.io.IOException;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.URI;
import java.util.Date;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class CookieCache extends CookieManager {

    private static Comparator<String> COOKIE_COMPARATOR = new CookieStringComparator();

    private static class CookieStringComparator implements Comparator<String> {
        private static final ThreadLocal<List<SimpleDateFormat>> formats;

        static {
            formats = new ThreadLocal<List<SimpleDateFormat>>() {
                @Override
                protected List<SimpleDateFormat> initialValue() {
                    List<SimpleDateFormat> list = new ArrayList<SimpleDateFormat>();
                    list.add(new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss 'GMT'", Locale.US));
                    list.add(new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm 'GMT'", Locale.US));
                    return Collections.unmodifiableList(list);
                }
            };
        }

        @Override
        public int compare(String o1, String o2) {
            Date d1 = parse(o1);
            Date d2 = parse(o2);

            return d1.compareTo(d2);
        }

        private Date parse(String string) {
            String expires = "expires=";
            int expiresIndex = string.indexOf(expires);

            if (expiresIndex != -1) {
                for (SimpleDateFormat sdf : formats.get()) {
                    Date d = sdf.parse(string, new ParsePosition(expiresIndex + expires.length()));
                    if (d != null) {
                        return d;
                    }
                }
            }
            return new Date();
        }

    }

    public CookieCache() {
        setCookiePolicy(CookiePolicy.ACCEPT_ALL);
    }

    @Override
    public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException {
        Map<String, List<String>> map = new HashMap<String, List<String>>();

        map.put("Set-Cookie", getCookieList("Set-Cookie", responseHeaders));
        map.put("Set-Cookie2", getCookieList("Set-Cookie2", responseHeaders));
        super.put(uri, map);
    }

    private List<String> getCookieList(String key, Map<String, List<String>> headers) {

        List<String> cookies = headers.get(key);

        if (cookies == null) {
            return null;
        }

        List<String> list = new ArrayList<String>(cookies);
        Collections.sort(list, COOKIE_COMPARATOR);
        return list;
    }
}
